﻿#include <xy/ais/curve.h>
#include <xy/alg/projection.h>

namespace xy
{

namespace ais
{

using namespace alg;
using namespace geom;

curve::curve(std::shared_ptr<geom::curve<3>> curve) : m_curve(curve)
{
}

std::vector<vec3f> curve::sample(std::size_t num) const
{
    auto [first, second] = m_curve->bound();

    std::vector<vec3f> samples;
    auto step = (second - first) / (num - 1);
    for (std::size_t i = 0; i < num; ++i)
        samples.push_back(convert<float>(m_curve->d0(first + step * i)));

    return samples;
}

std::shared_ptr<geom::curve<3>> curve::cur() const
{
    return m_curve;
}

bool curve::collision(msg_mouse *msg)
{
    vec3f P = msg->spaceMapping(msg->movePos);
    vec3f emit = (P - msg->camera->position()).normalize();

    vec3 Pd = convert<double>(P);
    vec3 emitd = convert<double>(emit);

    auto [first, second] = m_curve->bound();
    auto t = projection_point<3>::direction(m_curve, Pd, emitd, (first + second) / 2, 1e-2);

    // 如果小于指定深度，则记录下来
    auto Q = m_curve->d0(t);
    auto S = msg->screenMapping(convert<float>(Q));
    if (S.z() < msg->depth && cross((Pd - Q).normalize(), emitd).modulus() < 1e-2)
    {
        msg->depth = S.z();
        msg->captured = this;
        return true;
    }
    return false;
}

void curve::visit(msg_init *msg)
{
    if (msg->factory)
        m_renderer.reset(msg->factory->create_product("curve"));
}

curve_auxiliary::curve_auxiliary() : curve(nullptr)
{
}

void curve_auxiliary::add_point(std::shared_ptr<point_auxiliary> pnt)
{
    m_points.push_back(pnt);
}

std::vector<vec3f> curve_auxiliary::sample(std::size_t num) const
{
    std::vector<vec3f> result;
    for (auto &point : m_points)
        result.push_back(convert<float>(*point->pnt()));
    return result;
}

void curve_auxiliary::visit(msg_mouse *msg)
{
    // 空，移除 curve 的鼠标消息
}

} // namespace ais

} // namespace xy